package com.example.shiro.demo.shiro;

import com.example.shiro.demo.dao.UserRepository;
import com.example.shiro.demo.filter.*;
import com.example.shiro.demo.redis.CachingShiroSessionDao;
import com.example.shiro.demo.redis.RedisCacheManager;
import com.example.shiro.demo.service.ISyncCacheService;
import com.example.shiro.demo.shiro.security.JwtFilter;
import com.example.shiro.demo.shiro.security.JwtProperties;
import com.example.shiro.demo.shiro.security.SystemLogoutFilter;
import com.example.shiro.demo.util.JedisUtils;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import  org.apache.shiro.mgt.SecurityManager;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;

import java.util.Map;

/**
 * <Description> <br>
 *
 * @author renweiping<br>
 * @version 1.0<br>
 * @taskId: <br>
 * @createDate 2019/10/14 13:11 <br>
 * @see com.example.shiro.demo <br>
 */
@Configuration
public class ShiroConfig {

    private static final Logger log = LoggerFactory.getLogger(ShiroConfig.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private JedisUtils jedisUtils;

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator getLifecycleBeanPostProcessor() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    @Bean
    public SimpleCookie rememberMeCookie(){
        //System.out.println("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        return simpleCookie;
    }

    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager cacheManager = new RedisCacheManager();
        return  cacheManager;
    }

    @Bean
    public ExtendRolesAuthorizationFilter extendRolesAuthorizationFilter(){
        return new ExtendRolesAuthorizationFilter();
    }

    @Bean
    public URLPermissionsFilter uRLPermissionsFilter(){
        return new URLPermissionsFilter();
    }


    /**
     * cookie管理对象;
     * rememberMeManager()方法是生成rememberMe管理器，而且要将这个rememberMe管理器设置到securityManager中
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        log.info("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
        return cookieRememberMeManager;
    }


    //将自己的验证方式加入容器
    @Bean
    public CustomRealm myShiroRealm() {
        CustomRealm myShiroRealm = new CustomRealm();
        return myShiroRealm;
    }

    //权限管理，配置主要是Realm的管理认证
    @Bean
    public SecurityManager securityManager(ShiroRealm shiroRealm,CachingShiroSessionDao cachingShiroSessionDao) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置myShiroRealm
        securityManager.setRealm(shiroRealm);
        //用户授权/认证信息Cache, 采用redis缓存
        securityManager.setCacheManager(redisCacheManager());
        //注入记住我管理器
/*        securityManager.setRememberMeManager(rememberMeManager());*/

        //关闭shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);


        //自定义session管理
        securityManager.setSessionManager(sessionManager(cachingShiroSessionDao));

        return securityManager;
    }



    /**
     * 自定义sessionManager
     * @return
     */
    //@Bean
    public SessionManager sessionManager(CachingShiroSessionDao cachingShiroSessionDao ) {
        ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
        //这里可以不设置。Shiro有默认的session管理。如果缓存为Redis则需改用Redis的管理
        //shiroSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
        shiroSessionManager.setSessionDAO(cachingShiroSessionDao);
        return shiroSessionManager;
    }



    //Filter工厂，设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
                JwtProperties jwtProp, ISyncCacheService syncCacheService ) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
/*        Map<String,String> map = new HashMap<String, String>();
        //登出
        map.put("/logout","logout");
        //对所有用户认证
        map.put("/**","authc");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login");

        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面，认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        Map<String,Filter> filtersMap = shiroFilterFactoryBean.getFilters();
        filtersMap.put("authc",new ExtendFormAuthenticationFilter(userRepository));
        filtersMap.put("roleOrFilter",new ExtendRolesAuthorizationFilter());
        filtersMap.put("anyRoles",new AnyRolesFilter());
        filtersMap.put("perms",new URLPermissionsFilter());


        //
        shiroFilterFactoryBean.setFilters(filtersMap);

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);*/


        // 添加jwt过滤器
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JwtFilter(jwtProp,syncCacheService,jedisUtils));
        filterMap.put("logout", new SystemLogoutFilter(jedisUtils));
        shiroFilterFactoryBean.setFilters(filterMap);

        //动态配置拦截器注入
/*        Map<String, String> filterRuleMap = new HashMap<>(16);
        List<Map<String, String>> perms = this.getShiroFilterProperties().getPerms();
        perms.forEach(perm -> filterRuleMap.put(perm.get("key"), perm.get("value")));*/

        Map<String,String> map = new HashMap<String, String>();
        //登出
        map.put("/logout","logout");
        //对所有用户认证
        map.put("/**","jwt");

        map.put("/","anon");

        map.put("/login","anon");


        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }


    @Bean
    public ShiroFilterProperties getShiroFilterProperties(){
        return new ShiroFilterProperties();
    }


}
